Some renaming
authorMatthias Clasen <mclasen@redhat.com>
Thu, 27 Dec 2012 06:06:30 +0000 (01:06 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 27 Dec 2012 16:27:45 +0000 (11:27 -0500)
Move gail.h to gtkaccessibility.h, and libgail to libgtka11y.

gtk/Makefile.am
gtk/a11y/Makefile.am
gtk/a11y/gail.c [deleted file]
gtk/a11y/gail.h [deleted file]
gtk/a11y/gtkaccessibility.c [new file with mode: 0644]
gtk/a11y/gtkaccessibility.h [new file with mode: 0644]
gtk/gtkmain.c

index f0659f1285107f096c181fbfc6e5151344e6e9ce..81aef51a124cbe86acc131dfe5be8cdec08f7da9 100644 (file)
@@ -107,12 +107,12 @@ endif
 libgtkincludedir = $(includedir)/gtk-3.0/gtk
 libadd = \
        $(top_builddir)/gdk/libgdk-3.la \
-       $(top_builddir)/gtk/a11y/libgail.la \
+       $(top_builddir)/gtk/a11y/libgtka11y.la \
        $(GMODULE_LIBS) \
        $(GTK_DEP_LIBS)
 deps = \
        $(top_builddir)/gdk/libgdk-3.la \
-       $(top_builddir)/gtk/a11y/libgail.la
+       $(top_builddir)/gtk/a11y/libgtka11y.la
 
 # libtool stuff: set version and export symbols for resolving
 # since automake doesn't support conditionalized libsomething_la_LDFLAGS
index cc0bb7c7e186c11f9f04ce6feb8a5e4cb6a10a7b..66481a63cd8f857c042ff8acd47d74d780d32089 100644 (file)
@@ -1,9 +1,9 @@
 include $(top_srcdir)/Makefile.decl
 
-noinst_LTLIBRARIES = libgail.la
+noinst_LTLIBRARIES = libgtka11y.la
 
-gail_c_sources =                       \
-       gail.c                          \
+gtka11y_c_sources =                    \
+       gtkaccessibility.c              \
        gtkarrowaccessible.c            \
        gtkbooleancellaccessible.c      \
        gtkbuttonaccessible.c           \
@@ -104,15 +104,15 @@ gail_private_h_sources =          \
        gtktreeviewaccessibleprivate.h  \
        gtktextviewaccessibleprivate.h  \
        gtkwidgetaccessibleprivate.h    \
-       gail.h                          \
+       gtkaccessibility.h              \
        gailutil.h                      \
        gailmisc.h
 
-libgail_la_SOURCES =                   \
-       $(gail_c_sources)               \
-       $(gail_private_h_sources)
+libgtka11y_la_SOURCES =                \
+       $(gtka11y_c_sources)            \
+       $(gtka11y_private_h_sources)
 
-libgail_la_CPPFLAGS = \
+libgtka11y_la_CPPFLAGS =               \
        -I$(top_srcdir)                 \
        -I$(top_srcdir)/gdk             \
        -I$(top_builddir)/gdk           \
@@ -122,18 +122,18 @@ libgail_la_CPPFLAGS = \
        -DGTK_COMPILATION               \
        $(AM_CPPFLAGS)
 
-libgail_la_CFLAGS = \
-       $(GTK_DEP_CFLAGS)       \
-       $(GTK_DEBUG_FLAGS)      \
+libgtka11y_la_CFLAGS =                         \
+       $(GTK_DEP_CFLAGS)               \
+       $(GTK_DEBUG_FLAGS)              \
        $(AM_CFLAGS)
 
-libgail_la_LIBADD =  \
-       $(GTK_DEP_LIBS)         \
+libgtka11y_la_LIBADD =                 \
+       $(GTK_DEP_LIBS)                 \
        $(INTLLIBS)
 
-libgail_la_LDFLAGS =    \
+libgtka11y_la_LDFLAGS =                \
         $(LDFLAGS)
-               
+
 dist-hook: ../../build/win32/vs9/libgail.vcproj ../../build/win32/vs10/libgail.vcxproj ../../build/win32/vs10/libgail.vcxproj.filters
 
 ../../build/win32/vs9/libgail.vcproj: ../../build/win32/vs9/libgail.vcprojin
@@ -145,7 +145,7 @@ dist-hook: ../../build/win32/vs9/libgail.vcproj ../../build/win32/vs10/libgail.v
        done >libgail.sourcefiles
        $(CPP) -P - <$(top_srcdir)/build/win32/vs9/libgail.vcprojin >$@
        rm libgail.sourcefiles
-       
+
 ../../build/win32/vs10/libgail.vcxproj: ../../build/win32/vs10/libgail.vcxprojin
        for F in $(libgail_la_SOURCES); do \
                case $$F in \
diff --git a/gtk/a11y/gail.c b/gtk/a11y/gail.c
deleted file mode 100644 (file)
index 8f50846..0000000
+++ /dev/null
@@ -1,835 +0,0 @@
-/* GAIL - The GNOME Accessibility Implementation Library
- * Copyright 2001 Sun Microsystems Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include "gail.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <gdk/gdk.h>
-#include <gtk/gtkx.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtknotebook.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkmenubar.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtkcombobox.h>
-#include <gtk/gtkaccessible.h>
-#include "gailutil.h"
-#include "gailmisc.h"
-
-#ifdef GDK_WINDOWING_X11
-#include <atk-bridge.h>
-#endif
-
-static gboolean gail_focus_watcher      (GSignalInvocationHint *ihint,
-                                         guint                  n_param_values,
-                                         const GValue          *param_values,
-                                         gpointer               data);
-static gboolean gail_select_watcher     (GSignalInvocationHint *ihint,
-                                         guint                  n_param_values,
-                                         const GValue          *param_values,
-                                         gpointer               data);
-static gboolean gail_deselect_watcher   (GSignalInvocationHint *ihint,
-                                         guint                  n_param_values,
-                                         const GValue          *param_values,
-                                         gpointer               data);
-static gboolean gail_switch_page_watcher(GSignalInvocationHint *ihint,
-                                         guint                  n_param_values,
-                                         const GValue          *param_values,
-                                         gpointer               data);
-static void     gail_finish_select       (GtkWidget            *widget);
-static void     gail_map_cb              (GtkWidget            *widget);
-static void     gail_map_submenu_cb      (GtkWidget            *widget);
-static gint     gail_focus_idle_handler  (gpointer             data);
-static void     gail_focus_notify        (GtkWidget            *widget);
-static void     gail_focus_notify_when_idle (GtkWidget            *widget);
-
-static void     gail_focus_tracker_init (void);
-static void     gail_focus_object_destroyed (gpointer data);
-static void     gail_focus_tracker (AtkObject *object);
-static void     gail_set_focus_widget (GtkWidget *focus_widget,
-                                       GtkWidget *widget); 
-static void     gail_set_focus_object (AtkObject *focus_obj,
-                                       AtkObject *obj);
-
-GtkWidget* _focus_widget = NULL;
-static GtkWidget* next_focus_widget = NULL;
-static gboolean was_deselect = FALSE;
-static GtkWidget* subsequent_focus_widget = NULL;
-static GtkWidget* focus_before_menu = NULL;
-static guint focus_notify_handler = 0;    
-static guint focus_tracker_id = 0;
-static GQuark quark_focus_object = 0;
-static int initialized = FALSE;
-
-static AtkObject*
-gail_get_accessible_for_widget (GtkWidget *widget,
-                                gboolean  *transient)
-{
-  AtkObject *obj = NULL;
-
-  *transient = FALSE;
-  if (!widget)
-    return NULL;
-
-  if (GTK_IS_ENTRY (widget))
-    ;
-  else if (GTK_IS_NOTEBOOK (widget)) 
-    {
-      GtkNotebook *notebook;
-      gint page_num = -1;
-
-      notebook = GTK_NOTEBOOK (widget);
-      page_num = gtk_notebook_get_current_page (notebook);
-      if (page_num != -1)
-        {
-          obj = gtk_widget_get_accessible (widget);
-          obj = atk_object_ref_accessible_child (obj, page_num);
-          g_object_unref (obj);
-        }
-    }
-  else if (GTK_IS_TOGGLE_BUTTON (widget))
-    {
-      GtkWidget *other_widget = gtk_widget_get_parent (widget);
-      if (GTK_IS_COMBO_BOX (other_widget))
-        {
-          gail_set_focus_widget (other_widget, widget);
-          widget = other_widget;
-        }
-    }
-  if (obj == NULL)
-    {
-      AtkObject *focus_object;
-
-      obj = gtk_widget_get_accessible (widget);
-      focus_object = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
-      /*
-       * We check whether the object for this focus_object has been deleted.
-       * This can happen when navigating to an empty directory in nautilus. 
-       * See bug #141907.
-       */
-      if (ATK_IS_GOBJECT_ACCESSIBLE (focus_object))
-        {
-          if (!atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (focus_object)))
-            focus_object = NULL;
-        }
-      if (focus_object)
-        obj = focus_object;
-    }
-
-  return obj;
-}
-
-static gboolean
-gail_focus_watcher (GSignalInvocationHint *ihint,
-                    guint                  n_param_values,
-                    const GValue          *param_values,
-                    gpointer               data)
-{
-  GObject *object;
-  GtkWidget *widget;
-  GdkEvent *event;
-
-  object = g_value_get_object (param_values + 0);
-  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
-
-  event = g_value_get_boxed (param_values + 1);
-  widget = GTK_WIDGET (object);
-
-  if (event->type == GDK_FOCUS_CHANGE) 
-    {
-      if (event->focus_change.in)
-        {
-          if (GTK_IS_WINDOW (widget))
-            {
-              GtkWidget *focus_widget;
-              GtkWindow *window;
-              GtkWindowType type;
-
-              window = GTK_WINDOW (widget);
-              focus_widget = gtk_window_get_focus (window);
-              g_object_get (window, "type", &type, NULL);
-
-              if (focus_widget)
-                {
-                  /*
-                   * If we already have a potential focus widget set this
-                   * windows's focus widget to focus_before_menu so that 
-                   * it will be reported when menu item is unset.
-                   */
-                  if (next_focus_widget)
-                    {
-                      if (GTK_IS_MENU_ITEM (next_focus_widget) &&
-                          !focus_before_menu)
-                        {
-                          void *vp_focus_before_menu = &focus_before_menu;
-                          focus_before_menu = focus_widget;
-                          g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
-                        }
-
-                      return TRUE;
-                    }
-                  widget = focus_widget;
-                }
-              else if (type == GTK_WINDOW_POPUP)
-                {
-                 if (GTK_IS_BIN (widget))
-                   {
-                     GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
-
-                     if (GTK_IS_WIDGET (child) && gtk_widget_has_grab (child))
-                       {
-                         if (GTK_IS_MENU_SHELL (child))
-                           {
-                             if (gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (child)))
-                               {
-                                 /*
-                                  * We have a menu which has a menu item selected
-                                  * so we do not report focus on the menu.
-                                  */ 
-                                 return TRUE; 
-                               }
-                           }
-                         widget = child;
-                       } 
-                   }
-                 else /* popup window has no children; this edge case occurs in some custom code (OOo for instance) */
-                   {
-                     return TRUE;
-                   }
-                }
-             else /* Widget is a non-popup toplevel with no focus children; 
-                     don't emit for this case either, as it's useless */
-               {
-                 return TRUE;
-               }
-            }
-        }
-      else
-        {
-          if (next_focus_widget)
-            {
-               GtkWidget *toplevel;
-
-               toplevel = gtk_widget_get_toplevel (next_focus_widget);
-               if (toplevel == widget)
-                 next_focus_widget = NULL; 
-            }
-          /* focus out */
-          widget = NULL;
-        }
-    }
-  else
-    {
-      if (event->type == GDK_MOTION_NOTIFY && gtk_widget_has_focus (widget))
-        {
-          if (widget == _focus_widget)
-            {
-              return TRUE;
-            }
-        }
-      else
-        {
-          return TRUE;
-        }
-    }
-
-#ifdef GDK_WINDOWING_X11
-  /*
-   * If the focus widget is a GtkSocket without a plug
-   * then ignore the focus notification as the embedded
-   * plug will report a focus notification.
-   */
-  if (GTK_IS_SOCKET (widget) &&
-      gtk_socket_get_plug_window (GTK_SOCKET (widget)) != NULL)
-    return TRUE;
-#endif
-
-  /*
-   * The widget may not yet be visible on the screen so we wait until it is.
-   */
-  gail_focus_notify_when_idle (widget);
-  return TRUE; 
-}
-
-static gboolean
-gail_select_watcher (GSignalInvocationHint *ihint,
-                     guint                  n_param_values,
-                     const GValue          *param_values,
-                     gpointer               data)
-{
-  GObject *object;
-  GtkWidget *widget;
-
-  object = g_value_get_object (param_values + 0);
-  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
-
-  widget = GTK_WIDGET (object);
-
-  if (!gtk_widget_get_mapped (widget))
-    {
-      g_signal_connect (widget, "map",
-                        G_CALLBACK (gail_map_cb),
-                        NULL);
-    }
-  else
-    gail_finish_select (widget);
-
-  return TRUE;
-}
-
-static void
-gail_finish_select (GtkWidget *widget)
-{
-  if (GTK_IS_MENU_ITEM (widget))
-    {
-      GtkMenuItem* menu_item;
-      GtkWidget *submenu;
-
-      menu_item = GTK_MENU_ITEM (widget);
-      submenu = gtk_menu_item_get_submenu (menu_item);
-      if (submenu &&
-          !gtk_widget_get_mapped (submenu))
-        {
-          /*
-           * If the submenu is not visble, wait until it is before
-           * reporting focus on the menu item.
-           */
-          gulong handler_id;
-
-          handler_id = g_signal_handler_find (submenu,
-                                              G_SIGNAL_MATCH_FUNC,
-                                              g_signal_lookup ("map",
-                                                               GTK_TYPE_WINDOW),
-                                              0,
-                                              NULL,
-                                              (gpointer) gail_map_submenu_cb,
-                                              NULL); 
-          if (!handler_id)
-            g_signal_connect (submenu, "map",
-                              G_CALLBACK (gail_map_submenu_cb),
-                              NULL);
-            return;
-        }
-      /*
-       * If we are waiting to report focus on a menubar or a menu item
-       * because of a previous deselect, cancel it.
-       */
-      if (was_deselect &&
-          focus_notify_handler &&
-          next_focus_widget &&
-          (GTK_IS_MENU_BAR (next_focus_widget) ||
-           GTK_IS_MENU_ITEM (next_focus_widget)))
-        {
-          void *vp_next_focus_widget = &next_focus_widget;
-          g_source_remove (focus_notify_handler);
-          g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
-         next_focus_widget = NULL;
-          focus_notify_handler = 0;
-          was_deselect = FALSE;
-        }
-    } 
-  /*
-   * If previously focused widget is not a GtkMenuItem or a GtkMenu,
-   * keep track of it so we can return to it after menubar is deactivated
-   */
-  if (_focus_widget && 
-      !GTK_IS_MENU_ITEM (_focus_widget) && 
-      !GTK_IS_MENU (_focus_widget))
-    {
-      void *vp_focus_before_menu = &focus_before_menu;
-      focus_before_menu = _focus_widget;
-      g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
-
-    } 
-  gail_focus_notify_when_idle (widget);
-
-  return; 
-}
-
-static void
-gail_map_cb (GtkWidget *widget)
-{
-  gail_finish_select (widget);
-}
-
-static void
-gail_map_submenu_cb (GtkWidget *widget)
-{
-  if (GTK_IS_MENU (widget))
-    {
-      GtkWidget *parent_menu_item;
-
-      parent_menu_item = gtk_menu_get_attach_widget (GTK_MENU (widget));
-      if (parent_menu_item)
-        gail_finish_select (parent_menu_item);
-    }
-}
-
-
-static gboolean
-gail_deselect_watcher (GSignalInvocationHint *ihint,
-                       guint                  n_param_values,
-                       const GValue          *param_values,
-                       gpointer               data)
-{
-  GObject *object;
-  GtkWidget *widget;
-  GtkWidget *menu_shell;
-
-  object = g_value_get_object (param_values + 0);
-  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
-
-  widget = GTK_WIDGET (object);
-
-  if (!GTK_IS_MENU_ITEM (widget))
-    return TRUE;
-
-  if (subsequent_focus_widget == widget)
-    subsequent_focus_widget = NULL;
-
-  menu_shell = gtk_widget_get_parent (widget);
-  if (GTK_IS_MENU_SHELL (menu_shell))
-    {
-      GtkWidget *parent_menu_shell;
-
-      parent_menu_shell = gtk_menu_shell_get_parent_shell (GTK_MENU_SHELL (menu_shell));
-      if (parent_menu_shell)
-        {
-          GtkWidget *active_menu_item;
-
-          active_menu_item = gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (parent_menu_shell));
-          if (active_menu_item)
-            {
-              gail_focus_notify_when_idle (active_menu_item);
-            }
-        }
-      else
-        {
-          if (!GTK_IS_MENU_BAR (menu_shell))
-            {
-              gail_focus_notify_when_idle (menu_shell);
-            }
-        }
-    }
-  was_deselect = TRUE;
-  return TRUE; 
-}
-
-static gboolean 
-gail_switch_page_watcher (GSignalInvocationHint *ihint,
-                          guint                  n_param_values,
-                          const GValue          *param_values,
-                          gpointer               data)
-{
-  GObject *object;
-  GtkWidget *widget;
-
-  object = g_value_get_object (param_values + 0);
-  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
-
-  widget = GTK_WIDGET (object);
-
-  if (!GTK_IS_NOTEBOOK (widget))
-    return TRUE;
-
-  if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) == -1)
-    return TRUE;
-
-  gail_focus_notify_when_idle (widget);
-  return TRUE;
-}
-
-static gboolean
-gail_focus_idle_handler (gpointer data)
-{
-  focus_notify_handler = 0;
-  /*
-   * The widget which was to receive focus may have been removed
-   */
-  if (!next_focus_widget)
-    {
-      if (next_focus_widget != data)
-        return FALSE;
-    }
-  else
-    {
-      void *vp_next_focus_widget = &next_focus_widget;
-      g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
-      next_focus_widget = NULL;
-    }
-    
-  gail_focus_notify (data);
-
-  return FALSE;
-}
-
-static void
-gail_focus_notify (GtkWidget *widget)
-{
-  AtkObject *atk_obj;
-  gboolean transient;
-
-  if (widget != _focus_widget)
-    {
-      if (_focus_widget)
-        {
-          void *vp_focus_widget = &_focus_widget;
-          g_object_remove_weak_pointer (G_OBJECT (_focus_widget), vp_focus_widget);
-        }
-      _focus_widget = widget;
-      if (_focus_widget)
-        {
-          void *vp_focus_widget = &_focus_widget;
-          g_object_add_weak_pointer (G_OBJECT (_focus_widget), vp_focus_widget);
-          /*
-           * The UI may not have been updated yet; e.g. in gtkhtml2
-           * html_view_layout() is called in a idle handler
-           */
-          if (_focus_widget == focus_before_menu)
-            {
-              void *vp_focus_before_menu = &focus_before_menu;
-              g_object_remove_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
-              focus_before_menu = NULL;
-            }
-        }
-      gail_focus_notify_when_idle (_focus_widget);
-    }
-  else
-    {
-      if (_focus_widget)
-        atk_obj  = gail_get_accessible_for_widget (_focus_widget, &transient);
-      else
-        atk_obj = NULL;
-      /*
-       * Do not report focus on redundant object
-       */
-      if (atk_obj && 
-         (atk_object_get_role(atk_obj) != ATK_ROLE_REDUNDANT_OBJECT))
-         atk_focus_tracker_notify (atk_obj);
-      if (atk_obj && transient)
-        g_object_unref (atk_obj);
-      if (subsequent_focus_widget)
-        {
-          GtkWidget *tmp_widget = subsequent_focus_widget;
-          subsequent_focus_widget = NULL;
-          gail_focus_notify_when_idle (tmp_widget);
-        }
-    }
-}
-
-static void
-gail_focus_notify_when_idle (GtkWidget *widget)
-{
-  if (focus_notify_handler)
-    {
-      if (widget)
-        {
-          /*
-           * Ignore focus request when menu item is going to be focused.
-           * See bug #124232.
-           */
-          if (GTK_IS_MENU_ITEM (next_focus_widget) && !GTK_IS_MENU_ITEM (widget))
-            return;
-
-          if (next_focus_widget)
-            {
-              if (GTK_IS_MENU_ITEM (next_focus_widget) && GTK_IS_MENU_ITEM (widget))
-                {
-                  if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (next_focus_widget)) == gtk_widget_get_parent (widget))
-                    {
-                      if (subsequent_focus_widget)
-                        g_assert_not_reached ();
-                      subsequent_focus_widget = widget;
-                      return;
-                    } 
-                }
-            }
-          g_source_remove (focus_notify_handler);
-          if (next_focus_widget)
-           {
-             void *vp_next_focus_widget = &next_focus_widget;
-             g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
-             next_focus_widget = NULL;
-           }
-        }
-      else
-        /*
-         * Ignore if focus is being set to NULL and we are waiting to set focus
-         */
-        return;
-    }
-
-  if (widget)
-    {
-      void *vp_next_focus_widget = &next_focus_widget;
-      next_focus_widget = widget;
-      g_object_add_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
-    }
-  else
-    {
-      /*
-       * We are about to report focus as NULL so remove the weak pointer
-       * for the widget we were waiting to report focus on.
-       */ 
-      if (next_focus_widget)
-        {
-          void *vp_next_focus_widget = &next_focus_widget;
-          g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
-          next_focus_widget = NULL;
-        }
-    }
-
-  focus_notify_handler = gdk_threads_add_idle (gail_focus_idle_handler, widget);
-}
-
-static gboolean
-gail_deactivate_watcher (GSignalInvocationHint *ihint,
-                         guint                  n_param_values,
-                         const GValue          *param_values,
-                         gpointer               data)
-{
-  GObject *object;
-  GtkWidget *widget;
-  GtkMenuShell *shell;
-  GtkWidget *focus = NULL;
-
-  object = g_value_get_object (param_values + 0);
-  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
-  widget = GTK_WIDGET (object);
-
-  g_return_val_if_fail (GTK_IS_MENU_SHELL(widget), TRUE);
-  shell = GTK_MENU_SHELL(widget);
-  if (! gtk_menu_shell_get_parent_shell (shell))
-    focus = focus_before_menu;
-      
-  /*
-   * If we are waiting to report focus on a menubar or a menu item
-   * because of a previous deselect, cancel it.
-   */
-  if (was_deselect &&
-      focus_notify_handler &&
-      next_focus_widget &&
-      (GTK_IS_MENU_BAR (next_focus_widget) ||
-       GTK_IS_MENU_ITEM (next_focus_widget)))
-    {
-      void *vp_next_focus_widget = &next_focus_widget;
-      g_source_remove (focus_notify_handler);
-      g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
-      next_focus_widget = NULL;
-      focus_notify_handler = 0;
-      was_deselect = FALSE;
-    }
-  gail_focus_notify_when_idle (focus);
-
-  return TRUE; 
-}
-
-static void
-gail_focus_tracker_init (void)
-{
-  static gboolean  emission_hooks_added = FALSE;
-
-  if (!emission_hooks_added)
-    {
-      /*
-       * We cannot be sure that the classes exist so we make sure that they do.
-       */
-      g_type_class_ref (GTK_TYPE_WIDGET);
-      g_type_class_ref (GTK_TYPE_MENU_ITEM);
-      g_type_class_ref (GTK_TYPE_MENU_SHELL);
-      g_type_class_ref (GTK_TYPE_NOTEBOOK);
-
-      /*
-       * We listen for event_after signal and then check that the
-       * event was a focus in event so we get called after the event.
-       */
-      g_signal_add_emission_hook (
-             g_signal_lookup ("event-after", GTK_TYPE_WIDGET), 0,
-             gail_focus_watcher, NULL, (GDestroyNotify) NULL);
-      /*
-       * A "select" signal is emitted when arrow key is used to
-       * move to a list item in the popup window of a GtkCombo or
-       * a menu item in a menu.
-       */
-      g_signal_add_emission_hook (
-             g_signal_lookup ("select", GTK_TYPE_MENU_ITEM), 0,
-             gail_select_watcher, NULL, (GDestroyNotify) NULL);
-
-      /*
-       * A "deselect" signal is emitted when arrow key is used to
-       * move from a menu item in a menu to the parent menu.
-       */
-      g_signal_add_emission_hook (
-             g_signal_lookup ("deselect", GTK_TYPE_MENU_ITEM), 0,
-             gail_deselect_watcher, NULL, (GDestroyNotify) NULL);
-
-      /*
-       * We listen for deactivate signals on menushells to determine
-       * when the "focus" has left the menus.
-       */
-      g_signal_add_emission_hook (
-             g_signal_lookup ("deactivate", GTK_TYPE_MENU_SHELL), 0,
-             gail_deactivate_watcher, NULL, (GDestroyNotify) NULL);
-
-      /*
-       * We listen for "switch-page" signal on a GtkNotebook to notify
-       * when page has changed because of clicking on a notebook tab.
-       */
-      g_signal_add_emission_hook (
-             g_signal_lookup ("switch-page", GTK_TYPE_NOTEBOOK), 0,
-             gail_switch_page_watcher, NULL, (GDestroyNotify) NULL);
-      emission_hooks_added = TRUE;
-    }
-}
-
-static void
-gail_focus_object_destroyed (gpointer data)
-{
-  GObject *obj;
-
-  obj = G_OBJECT (data);
-  g_object_set_qdata (obj, quark_focus_object, NULL);
-  g_object_unref (obj); 
-}
-
-static void
-gail_focus_tracker (AtkObject *focus_object)
-{
-  /*
-   * Do not report focus on redundant object
-   */
-  if (focus_object && 
-      (atk_object_get_role(focus_object) != ATK_ROLE_REDUNDANT_OBJECT))
-    {
-      AtkObject *old_focus_object;
-
-      if (!GTK_IS_ACCESSIBLE (focus_object))
-        {
-          AtkObject *parent;
-
-          parent = focus_object;
-          while (1)
-            {
-              parent = atk_object_get_parent (parent);
-              if (parent == NULL)
-                break;
-              if (GTK_IS_ACCESSIBLE (parent))
-                break;
-            }
-
-          if (parent)
-            {
-              gail_set_focus_object (focus_object, parent);
-            }
-        }
-      else
-        {
-          old_focus_object = g_object_get_qdata (G_OBJECT (focus_object), quark_focus_object);
-          if (old_focus_object)
-            {
-              g_object_weak_unref (G_OBJECT (old_focus_object),
-                                   (GWeakNotify) gail_focus_object_destroyed,
-                                   focus_object);
-              g_object_set_qdata (G_OBJECT (focus_object), quark_focus_object, NULL);
-              g_object_unref (G_OBJECT (focus_object));
-            }
-        }
-    }
-}
-
-static void 
-gail_set_focus_widget (GtkWidget *focus_widget,
-                       GtkWidget *widget)
-{
-  AtkObject *focus_obj;
-  AtkObject *obj;
-
-  focus_obj = gtk_widget_get_accessible (focus_widget);
-  obj = gtk_widget_get_accessible (widget);
-  gail_set_focus_object (focus_obj, obj);
-}
-
-static void 
-gail_set_focus_object (AtkObject *focus_obj,
-                       AtkObject *obj)
-{
-  AtkObject *old_focus_obj;
-
-  old_focus_obj = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
-  if (old_focus_obj != obj)
-    {
-      if (old_focus_obj)
-        g_object_weak_unref (G_OBJECT (old_focus_obj),
-                             (GWeakNotify) gail_focus_object_destroyed,
-                             obj);
-      else
-        /*
-         * We call g_object_ref as if obj is destroyed 
-         * while the weak reference exists then destroying the 
-         * focus_obj would cause gail_focus_object_destroyed to be 
-         * called when obj is not a valid GObject.
-         */
-        g_object_ref (obj);
-
-      g_object_weak_ref (G_OBJECT (focus_obj),
-                         (GWeakNotify) gail_focus_object_destroyed,
-                         obj);
-      g_object_set_qdata (G_OBJECT (obj), quark_focus_object, focus_obj);
-    }
-}
-
-void
-_gtk_accessibility_shutdown (void)
-{
-  if (!initialized)
-    return;
-
-  initialized = FALSE;
-
-  g_clear_object (&atk_misc_instance);
-
-#ifdef GDK_WINDOWING_X11
-  atk_bridge_adaptor_cleanup ();
-#endif
-  _gail_util_uninstall ();
-}
-
-void
-_gtk_accessibility_init (void)
-{
-
-  if (initialized)
-    return;
-
-  initialized = TRUE;
-  quark_focus_object = g_quark_from_static_string ("gail-focus-object");
-
-  atk_focus_tracker_init (gail_focus_tracker_init);
-  focus_tracker_id = atk_add_focus_tracker (gail_focus_tracker);
-
-  _gail_util_install ();
-#ifdef GDK_WINDOWING_X11
-  atk_bridge_adaptor_init (NULL, NULL);
-#endif
-
-  atk_misc_instance = g_object_new (GAIL_TYPE_MISC, NULL);
-}
diff --git a/gtk/a11y/gail.h b/gtk/a11y/gail.h
deleted file mode 100644 (file)
index 6280451..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* GAIL - The GNOME Accessibility Implementation Library
- * Copyright 2001 Sun Microsystems Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GTK_GAIL_H__
-#define __GTK_GAIL_H__
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-void            _gtk_accessibility_shutdown             (void);
-void            _gtk_accessibility_init                 (void);
-
-G_END_DECLS
-
-#endif /* __GTK_GAIL_H__ */
diff --git a/gtk/a11y/gtkaccessibility.c b/gtk/a11y/gtkaccessibility.c
new file mode 100644 (file)
index 0000000..278762f
--- /dev/null
@@ -0,0 +1,834 @@
+/* GTK+ - accessibility implementations
+ * Copyright 2001 Sun Microsystems Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtkaccessibility.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gdk/gdk.h>
+#include <gtk/gtkx.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtknotebook.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenubar.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkcombobox.h>
+#include <gtk/gtkaccessible.h>
+#include "gailutil.h"
+#include "gailmisc.h"
+
+#ifdef GDK_WINDOWING_X11
+#include <atk-bridge.h>
+#endif
+
+static gboolean gail_focus_watcher      (GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static gboolean gail_select_watcher     (GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static gboolean gail_deselect_watcher   (GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static gboolean gail_switch_page_watcher(GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static void     gail_finish_select       (GtkWidget            *widget);
+static void     gail_map_cb              (GtkWidget            *widget);
+static void     gail_map_submenu_cb      (GtkWidget            *widget);
+static gint     gail_focus_idle_handler  (gpointer             data);
+static void     gail_focus_notify        (GtkWidget            *widget);
+static void     gail_focus_notify_when_idle (GtkWidget            *widget);
+
+static void     gail_focus_tracker_init (void);
+static void     gail_focus_object_destroyed (gpointer data);
+static void     gail_focus_tracker (AtkObject *object);
+static void     gail_set_focus_widget (GtkWidget *focus_widget,
+                                       GtkWidget *widget);
+static void     gail_set_focus_object (AtkObject *focus_obj,
+                                       AtkObject *obj);
+
+GtkWidget* _focus_widget = NULL;
+static GtkWidget* next_focus_widget = NULL;
+static gboolean was_deselect = FALSE;
+static GtkWidget* subsequent_focus_widget = NULL;
+static GtkWidget* focus_before_menu = NULL;
+static guint focus_notify_handler = 0;
+static guint focus_tracker_id = 0;
+static GQuark quark_focus_object = 0;
+static int initialized = FALSE;
+
+static AtkObject*
+get_accessible_for_widget (GtkWidget *widget,
+                           gboolean  *transient)
+{
+  AtkObject *obj = NULL;
+
+  *transient = FALSE;
+  if (!widget)
+    return NULL;
+
+  if (GTK_IS_ENTRY (widget))
+    ;
+  else if (GTK_IS_NOTEBOOK (widget)) 
+    {
+      GtkNotebook *notebook;
+      gint page_num = -1;
+
+      notebook = GTK_NOTEBOOK (widget);
+      page_num = gtk_notebook_get_current_page (notebook);
+      if (page_num != -1)
+        {
+          obj = gtk_widget_get_accessible (widget);
+          obj = atk_object_ref_accessible_child (obj, page_num);
+          g_object_unref (obj);
+        }
+    }
+  else if (GTK_IS_TOGGLE_BUTTON (widget))
+    {
+      GtkWidget *other_widget = gtk_widget_get_parent (widget);
+      if (GTK_IS_COMBO_BOX (other_widget))
+        {
+          gail_set_focus_widget (other_widget, widget);
+          widget = other_widget;
+        }
+    }
+  if (obj == NULL)
+    {
+      AtkObject *focus_object;
+
+      obj = gtk_widget_get_accessible (widget);
+      focus_object = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
+      /*
+       * We check whether the object for this focus_object has been deleted.
+       * This can happen when navigating to an empty directory in nautilus. 
+       * See bug #141907.
+       */
+      if (ATK_IS_GOBJECT_ACCESSIBLE (focus_object))
+        {
+          if (!atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (focus_object)))
+            focus_object = NULL;
+        }
+      if (focus_object)
+        obj = focus_object;
+    }
+
+  return obj;
+}
+
+static gboolean
+gail_focus_watcher (GSignalInvocationHint *ihint,
+                    guint                  n_param_values,
+                    const GValue          *param_values,
+                    gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  GdkEvent *event;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  event = g_value_get_boxed (param_values + 1);
+  widget = GTK_WIDGET (object);
+
+  if (event->type == GDK_FOCUS_CHANGE) 
+    {
+      if (event->focus_change.in)
+        {
+          if (GTK_IS_WINDOW (widget))
+            {
+              GtkWidget *focus_widget;
+              GtkWindow *window;
+              GtkWindowType type;
+
+              window = GTK_WINDOW (widget);
+              focus_widget = gtk_window_get_focus (window);
+              g_object_get (window, "type", &type, NULL);
+
+              if (focus_widget)
+                {
+                  /*
+                   * If we already have a potential focus widget set this
+                   * windows's focus widget to focus_before_menu so that 
+                   * it will be reported when menu item is unset.
+                   */
+                  if (next_focus_widget)
+                    {
+                      if (GTK_IS_MENU_ITEM (next_focus_widget) &&
+                          !focus_before_menu)
+                        {
+                          void *vp_focus_before_menu = &focus_before_menu;
+                          focus_before_menu = focus_widget;
+                          g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
+                        }
+
+                      return TRUE;
+                    }
+                  widget = focus_widget;
+                }
+              else if (type == GTK_WINDOW_POPUP)
+                {
+                 if (GTK_IS_BIN (widget))
+                   {
+                     GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
+
+                     if (GTK_IS_WIDGET (child) && gtk_widget_has_grab (child))
+                       {
+                         if (GTK_IS_MENU_SHELL (child))
+                           {
+                             if (gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (child)))
+                               {
+                                 /*
+                                  * We have a menu which has a menu item selected
+                                  * so we do not report focus on the menu.
+                                  */ 
+                                 return TRUE; 
+                               }
+                           }
+                         widget = child;
+                       } 
+                   }
+                 else /* popup window has no children; this edge case occurs in some custom code (OOo for instance) */
+                   {
+                     return TRUE;
+                   }
+                }
+             else /* Widget is a non-popup toplevel with no focus children; 
+                     don't emit for this case either, as it's useless */
+               {
+                 return TRUE;
+               }
+            }
+        }
+      else
+        {
+          if (next_focus_widget)
+            {
+               GtkWidget *toplevel;
+
+               toplevel = gtk_widget_get_toplevel (next_focus_widget);
+               if (toplevel == widget)
+                 next_focus_widget = NULL; 
+            }
+          /* focus out */
+          widget = NULL;
+        }
+    }
+  else
+    {
+      if (event->type == GDK_MOTION_NOTIFY && gtk_widget_has_focus (widget))
+        {
+          if (widget == _focus_widget)
+            {
+              return TRUE;
+            }
+        }
+      else
+        {
+          return TRUE;
+        }
+    }
+
+#ifdef GDK_WINDOWING_X11
+  /*
+   * If the focus widget is a GtkSocket without a plug
+   * then ignore the focus notification as the embedded
+   * plug will report a focus notification.
+   */
+  if (GTK_IS_SOCKET (widget) &&
+      gtk_socket_get_plug_window (GTK_SOCKET (widget)) != NULL)
+    return TRUE;
+#endif
+
+  /*
+   * The widget may not yet be visible on the screen so we wait until it is.
+   */
+  gail_focus_notify_when_idle (widget);
+  return TRUE; 
+}
+
+static gboolean
+gail_select_watcher (GSignalInvocationHint *ihint,
+                     guint                  n_param_values,
+                     const GValue          *param_values,
+                     gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  widget = GTK_WIDGET (object);
+
+  if (!gtk_widget_get_mapped (widget))
+    {
+      g_signal_connect (widget, "map",
+                        G_CALLBACK (gail_map_cb),
+                        NULL);
+    }
+  else
+    gail_finish_select (widget);
+
+  return TRUE;
+}
+
+static void
+gail_finish_select (GtkWidget *widget)
+{
+  if (GTK_IS_MENU_ITEM (widget))
+    {
+      GtkMenuItem* menu_item;
+      GtkWidget *submenu;
+
+      menu_item = GTK_MENU_ITEM (widget);
+      submenu = gtk_menu_item_get_submenu (menu_item);
+      if (submenu &&
+          !gtk_widget_get_mapped (submenu))
+        {
+          /*
+           * If the submenu is not visble, wait until it is before
+           * reporting focus on the menu item.
+           */
+          gulong handler_id;
+
+          handler_id = g_signal_handler_find (submenu,
+                                              G_SIGNAL_MATCH_FUNC,
+                                              g_signal_lookup ("map",
+                                                               GTK_TYPE_WINDOW),
+                                              0,
+                                              NULL,
+                                              (gpointer) gail_map_submenu_cb,
+                                              NULL); 
+          if (!handler_id)
+            g_signal_connect (submenu, "map",
+                              G_CALLBACK (gail_map_submenu_cb),
+                              NULL);
+            return;
+        }
+      /*
+       * If we are waiting to report focus on a menubar or a menu item
+       * because of a previous deselect, cancel it.
+       */
+      if (was_deselect &&
+          focus_notify_handler &&
+          next_focus_widget &&
+          (GTK_IS_MENU_BAR (next_focus_widget) ||
+           GTK_IS_MENU_ITEM (next_focus_widget)))
+        {
+          void *vp_next_focus_widget = &next_focus_widget;
+          g_source_remove (focus_notify_handler);
+          g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+         next_focus_widget = NULL;
+          focus_notify_handler = 0;
+          was_deselect = FALSE;
+        }
+    } 
+  /*
+   * If previously focused widget is not a GtkMenuItem or a GtkMenu,
+   * keep track of it so we can return to it after menubar is deactivated
+   */
+  if (_focus_widget && 
+      !GTK_IS_MENU_ITEM (_focus_widget) && 
+      !GTK_IS_MENU (_focus_widget))
+    {
+      void *vp_focus_before_menu = &focus_before_menu;
+      focus_before_menu = _focus_widget;
+      g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
+
+    } 
+  gail_focus_notify_when_idle (widget);
+
+  return; 
+}
+
+static void
+gail_map_cb (GtkWidget *widget)
+{
+  gail_finish_select (widget);
+}
+
+static void
+gail_map_submenu_cb (GtkWidget *widget)
+{
+  if (GTK_IS_MENU (widget))
+    {
+      GtkWidget *parent_menu_item;
+
+      parent_menu_item = gtk_menu_get_attach_widget (GTK_MENU (widget));
+      if (parent_menu_item)
+        gail_finish_select (parent_menu_item);
+    }
+}
+
+
+static gboolean
+gail_deselect_watcher (GSignalInvocationHint *ihint,
+                       guint                  n_param_values,
+                       const GValue          *param_values,
+                       gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  GtkWidget *menu_shell;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  widget = GTK_WIDGET (object);
+
+  if (!GTK_IS_MENU_ITEM (widget))
+    return TRUE;
+
+  if (subsequent_focus_widget == widget)
+    subsequent_focus_widget = NULL;
+
+  menu_shell = gtk_widget_get_parent (widget);
+  if (GTK_IS_MENU_SHELL (menu_shell))
+    {
+      GtkWidget *parent_menu_shell;
+
+      parent_menu_shell = gtk_menu_shell_get_parent_shell (GTK_MENU_SHELL (menu_shell));
+      if (parent_menu_shell)
+        {
+          GtkWidget *active_menu_item;
+
+          active_menu_item = gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (parent_menu_shell));
+          if (active_menu_item)
+            {
+              gail_focus_notify_when_idle (active_menu_item);
+            }
+        }
+      else
+        {
+          if (!GTK_IS_MENU_BAR (menu_shell))
+            {
+              gail_focus_notify_when_idle (menu_shell);
+            }
+        }
+    }
+  was_deselect = TRUE;
+  return TRUE; 
+}
+
+static gboolean 
+gail_switch_page_watcher (GSignalInvocationHint *ihint,
+                          guint                  n_param_values,
+                          const GValue          *param_values,
+                          gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  widget = GTK_WIDGET (object);
+
+  if (!GTK_IS_NOTEBOOK (widget))
+    return TRUE;
+
+  if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) == -1)
+    return TRUE;
+
+  gail_focus_notify_when_idle (widget);
+  return TRUE;
+}
+
+static gboolean
+gail_focus_idle_handler (gpointer data)
+{
+  focus_notify_handler = 0;
+  /*
+   * The widget which was to receive focus may have been removed
+   */
+  if (!next_focus_widget)
+    {
+      if (next_focus_widget != data)
+        return FALSE;
+    }
+  else
+    {
+      void *vp_next_focus_widget = &next_focus_widget;
+      g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+      next_focus_widget = NULL;
+    }
+    
+  gail_focus_notify (data);
+
+  return FALSE;
+}
+
+static void
+gail_focus_notify (GtkWidget *widget)
+{
+  AtkObject *atk_obj;
+  gboolean transient;
+
+  if (widget != _focus_widget)
+    {
+      if (_focus_widget)
+        {
+          void *vp_focus_widget = &_focus_widget;
+          g_object_remove_weak_pointer (G_OBJECT (_focus_widget), vp_focus_widget);
+        }
+      _focus_widget = widget;
+      if (_focus_widget)
+        {
+          void *vp_focus_widget = &_focus_widget;
+          g_object_add_weak_pointer (G_OBJECT (_focus_widget), vp_focus_widget);
+          /*
+           * The UI may not have been updated yet; e.g. in gtkhtml2
+           * html_view_layout() is called in a idle handler
+           */
+          if (_focus_widget == focus_before_menu)
+            {
+              void *vp_focus_before_menu = &focus_before_menu;
+              g_object_remove_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
+              focus_before_menu = NULL;
+            }
+        }
+      gail_focus_notify_when_idle (_focus_widget);
+    }
+  else
+    {
+      if (_focus_widget)
+        atk_obj  = get_accessible_for_widget (_focus_widget, &transient);
+      else
+        atk_obj = NULL;
+      /*
+       * Do not report focus on redundant object
+       */
+      if (atk_obj &&
+         (atk_object_get_role(atk_obj) != ATK_ROLE_REDUNDANT_OBJECT))
+         atk_focus_tracker_notify (atk_obj);
+      if (atk_obj && transient)
+        g_object_unref (atk_obj);
+      if (subsequent_focus_widget)
+        {
+          GtkWidget *tmp_widget = subsequent_focus_widget;
+          subsequent_focus_widget = NULL;
+          gail_focus_notify_when_idle (tmp_widget);
+        }
+    }
+}
+
+static void
+gail_focus_notify_when_idle (GtkWidget *widget)
+{
+  if (focus_notify_handler)
+    {
+      if (widget)
+        {
+          /*
+           * Ignore focus request when menu item is going to be focused.
+           * See bug #124232.
+           */
+          if (GTK_IS_MENU_ITEM (next_focus_widget) && !GTK_IS_MENU_ITEM (widget))
+            return;
+
+          if (next_focus_widget)
+            {
+              if (GTK_IS_MENU_ITEM (next_focus_widget) && GTK_IS_MENU_ITEM (widget))
+                {
+                  if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (next_focus_widget)) == gtk_widget_get_parent (widget))
+                    {
+                      if (subsequent_focus_widget)
+                        g_assert_not_reached ();
+                      subsequent_focus_widget = widget;
+                      return;
+                    } 
+                }
+            }
+          g_source_remove (focus_notify_handler);
+          if (next_focus_widget)
+           {
+             void *vp_next_focus_widget = &next_focus_widget;
+             g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+             next_focus_widget = NULL;
+           }
+        }
+      else
+        /*
+         * Ignore if focus is being set to NULL and we are waiting to set focus
+         */
+        return;
+    }
+
+  if (widget)
+    {
+      void *vp_next_focus_widget = &next_focus_widget;
+      next_focus_widget = widget;
+      g_object_add_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+    }
+  else
+    {
+      /*
+       * We are about to report focus as NULL so remove the weak pointer
+       * for the widget we were waiting to report focus on.
+       */ 
+      if (next_focus_widget)
+        {
+          void *vp_next_focus_widget = &next_focus_widget;
+          g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+          next_focus_widget = NULL;
+        }
+    }
+
+  focus_notify_handler = gdk_threads_add_idle (gail_focus_idle_handler, widget);
+}
+
+static gboolean
+gail_deactivate_watcher (GSignalInvocationHint *ihint,
+                         guint                  n_param_values,
+                         const GValue          *param_values,
+                         gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  GtkMenuShell *shell;
+  GtkWidget *focus = NULL;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+  widget = GTK_WIDGET (object);
+
+  g_return_val_if_fail (GTK_IS_MENU_SHELL(widget), TRUE);
+  shell = GTK_MENU_SHELL(widget);
+  if (! gtk_menu_shell_get_parent_shell (shell))
+    focus = focus_before_menu;
+      
+  /*
+   * If we are waiting to report focus on a menubar or a menu item
+   * because of a previous deselect, cancel it.
+   */
+  if (was_deselect &&
+      focus_notify_handler &&
+      next_focus_widget &&
+      (GTK_IS_MENU_BAR (next_focus_widget) ||
+       GTK_IS_MENU_ITEM (next_focus_widget)))
+    {
+      void *vp_next_focus_widget = &next_focus_widget;
+      g_source_remove (focus_notify_handler);
+      g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+      next_focus_widget = NULL;
+      focus_notify_handler = 0;
+      was_deselect = FALSE;
+    }
+  gail_focus_notify_when_idle (focus);
+
+  return TRUE; 
+}
+
+static void
+gail_focus_tracker_init (void)
+{
+  static gboolean  emission_hooks_added = FALSE;
+
+  if (!emission_hooks_added)
+    {
+      /*
+       * We cannot be sure that the classes exist so we make sure that they do.
+       */
+      g_type_class_ref (GTK_TYPE_WIDGET);
+      g_type_class_ref (GTK_TYPE_MENU_ITEM);
+      g_type_class_ref (GTK_TYPE_MENU_SHELL);
+      g_type_class_ref (GTK_TYPE_NOTEBOOK);
+
+      /*
+       * We listen for event_after signal and then check that the
+       * event was a focus in event so we get called after the event.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("event-after", GTK_TYPE_WIDGET), 0,
+             gail_focus_watcher, NULL, (GDestroyNotify) NULL);
+      /*
+       * A "select" signal is emitted when arrow key is used to
+       * move to a list item in the popup window of a GtkCombo or
+       * a menu item in a menu.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("select", GTK_TYPE_MENU_ITEM), 0,
+             gail_select_watcher, NULL, (GDestroyNotify) NULL);
+
+      /*
+       * A "deselect" signal is emitted when arrow key is used to
+       * move from a menu item in a menu to the parent menu.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("deselect", GTK_TYPE_MENU_ITEM), 0,
+             gail_deselect_watcher, NULL, (GDestroyNotify) NULL);
+
+      /*
+       * We listen for deactivate signals on menushells to determine
+       * when the "focus" has left the menus.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("deactivate", GTK_TYPE_MENU_SHELL), 0,
+             gail_deactivate_watcher, NULL, (GDestroyNotify) NULL);
+
+      /*
+       * We listen for "switch-page" signal on a GtkNotebook to notify
+       * when page has changed because of clicking on a notebook tab.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("switch-page", GTK_TYPE_NOTEBOOK), 0,
+             gail_switch_page_watcher, NULL, (GDestroyNotify) NULL);
+      emission_hooks_added = TRUE;
+    }
+}
+
+static void
+gail_focus_object_destroyed (gpointer data)
+{
+  GObject *obj;
+
+  obj = G_OBJECT (data);
+  g_object_set_qdata (obj, quark_focus_object, NULL);
+  g_object_unref (obj); 
+}
+
+static void
+gail_focus_tracker (AtkObject *focus_object)
+{
+  /*
+   * Do not report focus on redundant object
+   */
+  if (focus_object && 
+      (atk_object_get_role(focus_object) != ATK_ROLE_REDUNDANT_OBJECT))
+    {
+      AtkObject *old_focus_object;
+
+      if (!GTK_IS_ACCESSIBLE (focus_object))
+        {
+          AtkObject *parent;
+
+          parent = focus_object;
+          while (1)
+            {
+              parent = atk_object_get_parent (parent);
+              if (parent == NULL)
+                break;
+              if (GTK_IS_ACCESSIBLE (parent))
+                break;
+            }
+
+          if (parent)
+            {
+              gail_set_focus_object (focus_object, parent);
+            }
+        }
+      else
+        {
+          old_focus_object = g_object_get_qdata (G_OBJECT (focus_object), quark_focus_object);
+          if (old_focus_object)
+            {
+              g_object_weak_unref (G_OBJECT (old_focus_object),
+                                   (GWeakNotify) gail_focus_object_destroyed,
+                                   focus_object);
+              g_object_set_qdata (G_OBJECT (focus_object), quark_focus_object, NULL);
+              g_object_unref (G_OBJECT (focus_object));
+            }
+        }
+    }
+}
+
+static void 
+gail_set_focus_widget (GtkWidget *focus_widget,
+                       GtkWidget *widget)
+{
+  AtkObject *focus_obj;
+  AtkObject *obj;
+
+  focus_obj = gtk_widget_get_accessible (focus_widget);
+  obj = gtk_widget_get_accessible (widget);
+  gail_set_focus_object (focus_obj, obj);
+}
+
+static void 
+gail_set_focus_object (AtkObject *focus_obj,
+                       AtkObject *obj)
+{
+  AtkObject *old_focus_obj;
+
+  old_focus_obj = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
+  if (old_focus_obj != obj)
+    {
+      if (old_focus_obj)
+        g_object_weak_unref (G_OBJECT (old_focus_obj),
+                             (GWeakNotify) gail_focus_object_destroyed,
+                             obj);
+      else
+        /*
+         * We call g_object_ref as if obj is destroyed 
+         * while the weak reference exists then destroying the 
+         * focus_obj would cause gail_focus_object_destroyed to be 
+         * called when obj is not a valid GObject.
+         */
+        g_object_ref (obj);
+
+      g_object_weak_ref (G_OBJECT (focus_obj),
+                         (GWeakNotify) gail_focus_object_destroyed,
+                         obj);
+      g_object_set_qdata (G_OBJECT (obj), quark_focus_object, focus_obj);
+    }
+}
+
+void
+_gtk_accessibility_shutdown (void)
+{
+  if (!initialized)
+    return;
+
+  initialized = FALSE;
+
+  g_clear_object (&atk_misc_instance);
+
+#ifdef GDK_WINDOWING_X11
+  atk_bridge_adaptor_cleanup ();
+#endif
+  _gail_util_uninstall ();
+}
+
+void
+_gtk_accessibility_init (void)
+{
+  if (initialized)
+    return;
+
+  initialized = TRUE;
+  quark_focus_object = g_quark_from_static_string ("gail-focus-object");
+
+  atk_focus_tracker_init (gail_focus_tracker_init);
+  focus_tracker_id = atk_add_focus_tracker (gail_focus_tracker);
+
+  _gail_util_install ();
+#ifdef GDK_WINDOWING_X11
+  atk_bridge_adaptor_init (NULL, NULL);
+#endif
+
+  atk_misc_instance = g_object_new (GAIL_TYPE_MISC, NULL);
+}
diff --git a/gtk/a11y/gtkaccessibility.h b/gtk/a11y/gtkaccessibility.h
new file mode 100644 (file)
index 0000000..437bc0e
--- /dev/null
@@ -0,0 +1,30 @@
+/* GTK+ - accessibility implementations
+ * Copyright 2001 Sun Microsystems Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_ACCESSIBILITY_H__
+#define __GTK_ACCESSIBILITY_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+void _gtk_accessibility_shutdown (void);
+void _gtk_accessibility_init     (void);
+
+G_END_DECLS
+
+#endif /* __GTK_ACCESSIBILITY_H__ */
index 86cf7c862673bfba93bc53496ad9a9082149bdc4..889813eb66a0196e0f5363f44587e372b9b81095 100644 (file)
 #include "gtkwidgetprivate.h"
 #include "gtkwindowprivate.h"
 
-#include "a11y/gail.h"
+#include "a11y/gtkaccessibility.h"
 #include "a11y/gailutil.h"
 
 /* Private type definitions